package org.tools.file;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;

import org.tools.common.BeanUtil;
import org.tools.constants.StringPool;
import org.tools.string.StringUtil;

/** 
 * 文件操作工具
 * <pre> 
 * 构建组：e-tools
 * 作者：eddy
 * 邮箱：xqxyxchy@126.com
 * 日期：2017年4月14日-下午8:51:56
 * </pre>
 */
public class FileUtil {
	public static final String ANY = "*";
	
	public static List<File> list(String path){
		return list(path, ANY);
	}
	
	public static List<File> list(String path, final String fileName){
		return list(path, fileName, -1);
	}
	
	public static List<File> list(String path, final String fileName, int level){
		if(level == 0){
			return null;
		}
		
		if(StringUtil.isBlank(path)){
			return null;
		}
		
		File parent = new File(path);
		if(!parent.exists()){
			return null;
		}
		
		if(parent.isFile()){
			return null;
		}
		
		List<File> rsList = new ArrayList<File>();
		List<File> _rsList = null;
		File[] rsFiles = null;
		if(ANY.equals(fileName)){
			rsFiles = parent.listFiles();
			if(BeanUtil.isNotEmpty(rsFiles)){
				for(File file : rsFiles){
					if(file.isFile()){
						rsList.add(file);
					}else{
						_rsList = list(file.getAbsolutePath(), fileName, level - 1);
						if(BeanUtil.isNotEmpty(_rsList)){
							rsList.addAll(_rsList);
						}
					}
				}
			}
		}else{
			rsFiles = parent.listFiles(new FileFilter() {
				public boolean accept(File pathname) {
					return pathname.isFile() && pathname.getName().equalsIgnoreCase(fileName);
				}
			});
			if(BeanUtil.isNotEmpty(rsFiles)){
				rsList.addAll(Arrays.asList(rsFiles));
			}
			
			File[] _rsFiles = parent.listFiles(new FileFilter() {
				public boolean accept(File pathname) {
					return pathname.isDirectory();
				}
			});
			if(BeanUtil.isNotEmpty(_rsFiles)){
				for(File file : _rsFiles){
					_rsList = list(file.getAbsolutePath(), fileName, level - 1);
					if(BeanUtil.isNotEmpty(_rsList)){
						rsList.addAll(_rsList);
					}
				}
			}
		}
		
		return rsList;
	}
	
	public static void console(List<File> files){
		if(BeanUtil.isNotEmpty(files)){
			for(File file : files){
				System.out.println("match file:" + file.getPath());
			}
			System.out.println("files.size() is " + files.size());
		}
	}
	
	public static void console(File file){
		if(BeanUtil.isNotEmpty(file)){
			System.out.println("match file:" + file.getPath());
		}
	}
	
	/////////////////////////////////////////////////////////
	
	/**
	 * 写入文件.(以默认UTF-8方式)
	 * 
	 * @param fileName
	 *            文件名称
	 * @param content
	 *            文件内容
	 */
	public static void writeFile(String fileName, String content) {
		writeFile(fileName, content, StringPool.UTF_8);
	}

	/**
	 * 指定字符集，写入文件。
	 * 
	 * @param fileName
	 *            文件名称
	 * @param content
	 * @param charset
	 */
	public static void writeFile(String fileName, String content, String charset) {
		Writer out = null;
		try {
			createFolder(fileName, true);
			out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName), charset));
			out.write(content);

		} catch (IOException e) {
			throw new RuntimeException(e);
		} finally {
			try {
				if (out != null){
					out.close();
				}
			} catch (IOException ignore) {
			}
		}
	}

	/**
	 * 写入文件
	 * 
	 * @param fileName
	 * @param is
	 * @throws IOException
	 */
	public static void writeFile(String fileName, InputStream is) throws IOException {
		FileOutputStream fos = new FileOutputStream(fileName);
		byte[] bs = new byte[512];
		int n = 0;
		while ((n = is.read(bs)) != -1) {
			fos.write(bs, 0, n);
		}
		is.close();
		fos.close();
	}

	/**
	 * 读取文件
	 * 
	 * @param fileName
	 *            文件路径
	 * @param charset
	 *            编码
	 * @return
	 */
	public static String readFile(String filePath, String charset, boolean isLine) {
		try {
			StringBuffer sb = new StringBuffer();
			BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), charset));
			String str;
			while ((str = in.readLine()) != null) {
				sb.append(str + (isLine ? "\r\n" : ""));
			}
			in.close();
			return sb.toString();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 读取文件
	 * 
	 * @param fileName
	 *            文件路径
	 * @param charset
	 *            编码
	 * @return
	 */
	public static String readFile(String filePath, String charset) {
		return readFile(filePath, charset, true);
	}

	/**
	 * 读取文件
	 * 
	 * @param fileName
	 *            文件路径
	 * @return
	 */
	public static String readFile(String filePath) {
		try {
			File file = new File(filePath);
			String charset = getCharset(file);
			return readFile(filePath, charset);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 通过类路径读取文件
	 * 
	 * @param filePath
	 *            文件类路径
	 * @return
	 */
	public static String readByClassPath(String filePath) {
		return readByClassPath(filePath, null);
	}

	/**
	 * 读取类路径下的文件。
	 * 
	 * @param filePath
	 * @param classLoader
	 * @return
	 */
	public static String readByClassPath(String filePath, ClassLoader classLoader) {
		InputStream is = null;
		try {
			URL url = null;
			if (classLoader != null) {
				url = classLoader.getResource("/" + filePath);
			} else {
				url = FileUtil.class.getResource("/" + filePath);
			}

			is = url.openStream();

			InputStreamReader isr = new InputStreamReader(is);

			BufferedReader br = new BufferedReader(isr);

			String s = null;
			String fileText = "";
			while ((s = br.readLine()) != null) {
				fileText = fileText + s + "\r\n";
			}

			return fileText;
		} catch (IOException e) {
			throw new RuntimeException(e);
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException ignore) {
				}
			}
		}
	}

	/**
	 * 判断文件是否存在
	 * 
	 * @param dir
	 * @return
	 */
	public static boolean isExistFile(String dir) {
		boolean isExist = false;
		File fileDir = new File(dir);
		if (fileDir.isDirectory()) {
			File[] files = fileDir.listFiles();
			if (files != null && files.length != 0)
				isExist = true;
		}
		return isExist;
	}

	/**
	 * 获取文件的字符集
	 * 
	 * @param file
	 * @return
	 */
	public static String getCharset(File file) {
		String charset = StringPool.GBK;
		byte[] first3Bytes = new byte[3];
		BufferedInputStream bis = null;
		try {
			boolean checked = false;
			bis = new BufferedInputStream(new FileInputStream(file));
			bis.mark(0);
			int read = bis.read(first3Bytes, 0, 3);
			if (read == -1)
				return charset;

			if (first3Bytes[0] == (byte) 0xFF && first3Bytes[1] == (byte) 0xFE) {
				charset = "UTF-16LE";
				checked = true;
			} else if (first3Bytes[0] == (byte) 0xFE && first3Bytes[1] == (byte) 0xFF) {
				charset = "UTF-16BE";
				checked = true;
			} else if (first3Bytes[0] == (byte) 0xEF && first3Bytes[1] == (byte) 0xBB
					&& first3Bytes[2] == (byte) 0xBF) {
				charset = "UTF-8";
				checked = true;
			}
			bis.reset();

			if (!checked) {
				// int loc = 0;
				while ((read = bis.read()) != -1) {
					// loc++;
					if (read >= 0xF0)
						break;
					// 单独出现BF以下的，也算是GBK
					if (0x80 <= read && read <= 0xBF)
						break;
					if (0xC0 <= read && read <= 0xDF) {
						read = bis.read();
						if (0x80 <= read && read <= 0xBF)// 双字节 (0xC0 - 0xDF)
							// (0x80 -
							// 0xBF),也可能在GB编码内
							continue;
						else
							break;
						// 也有可能出错，但是几率较小
					} else if (0xE0 <= read && read <= 0xEF) {
						read = bis.read();
						if (0x80 <= read && read <= 0xBF) {
							read = bis.read();
							if (0x80 <= read && read <= 0xBF) {
								charset = StringPool.UTF_8;
								break;
							} else
								break;
						} else
							break;
					}
				}

			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			if (bis != null)
				try {
					bis.close();
				} catch (IOException ignore) {
				}
		}

		return charset;
	}

	/**
	 * 读取流到字节数组
	 * 
	 * @param is
	 * @return
	 */
	public static byte[] readByte(InputStream is) {
		try {
			byte[] r = new byte[is.available()];
			is.read(r);
			return r;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 读取文件到字节数组
	 * 
	 * @param fileName
	 * @return
	 */
	public static byte[] readByte(String fileName) {
		try {
			FileInputStream fis = new FileInputStream(fileName);
			byte[] r = new byte[fis.available()];
			fis.read(r);
			fis.close();
			return r;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 写字节数组到文件
	 * 
	 * @param fileName
	 * @param b
	 * @return
	 */
	public static boolean writeByte(String fileName, byte[] b) {
		BufferedOutputStream fos = null;
		try {
			fos = new BufferedOutputStream(new FileOutputStream(fileName));
			fos.write(b);
			fos.close();
			return true;
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException ignore) {
				}
			}
		}
	}

	/**
	 * 删除目录
	 * 
	 * @param dir
	 * @return
	 */
	public static boolean deleteDir(File dir) {
		if (dir.isDirectory()) {
			String[] children = dir.list();
			for (int i = 0; i < children.length; i++) {
				boolean success = deleteDir(new File(dir, children[i]));
				if (!success)
					return false;
			}
		}
		return dir.delete();
	}

	/**
	 * 序列化对象到文件
	 * 
	 * @param obj
	 * @param fileName
	 */
	public static void serializeToFile(Object obj, String fileName) {
		try {
			ObjectOutput out = new ObjectOutputStream(new FileOutputStream(fileName));
			out.writeObject(obj);
			out.close();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 从文件反序列化出对象
	 * 
	 * @param fileName
	 * @return
	 */
	public static Object deserializeFromFile(String fileName) {
		try {
			File file = new File(fileName);
			ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
			Object obj = in.readObject();
			in.close();
			return obj;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * InputStream 转为字符串
	 * 
	 * @param input
	 * @param charset
	 * @return
	 * @throws IOException
	 */
	public static String inputStream2String(InputStream input, String charset) throws IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(input, charset));
		StringBuffer buffer = new StringBuffer();
		String line = "";
		while ((line = in.readLine()) != null) {
			buffer.append(line + "\n");
		}
		return buffer.toString();
	}

	/**
	 * 将stream按照utf-8编码转换为字符串。
	 * 
	 * @param input
	 * @return
	 * @throws IOException
	 */
	public static String inputStream2String(InputStream input) throws IOException {
		return inputStream2String(input, StringPool.UTF_8);
	}

	/**
	 * 根据目录取得文件列表
	 * 
	 * @param path
	 * @return
	 */
	public static File[] getFiles(String path) {
		File file = new File(path);
		return file.listFiles();
	}

	/**
	 * 创建文件目录
	 * 
	 * @param filePath
	 * @param fileName
	 *            文件名称
	 * @return 文件的完整目录
	 */
	public static String createFile(String filePath, String fileName) {
		File file = new File(filePath);
		// 文件夹不存在创建
		if (!file.exists())
			file.mkdirs();
		return file.getPath() + File.separator + fileName;
	}

	/**
	 * 根据文件路径创建文件夹,如果路径不存在则创建.
	 * 
	 * @param path
	 */
	public static void createFolderFile(String path) {
		createFolder(path, true);
	}

	/**
	 * 创建文件夹
	 * 
	 * @param path
	 * @param isFile
	 */
	public static void createFolder(String path, boolean isFile) {
		if (isFile)
			path = path.substring(0, path.lastIndexOf(File.separator));
		File file = new File(path);
		if (!file.exists())
			file.mkdirs();
	}

	/**
	 * 复制文件来新路径上
	 * 
	 * @param path
	 *            原路径
	 * @param newPath
	 *            新路径
	 */
	public static void renameFolder(String path, String newName) {
		File file = new File(path);
		if (file.exists())
			file.renameTo(new File(newName));
	}

	/**
	 * 仅取得文件目录下的子目录。
	 * 
	 * @param dir
	 *            目录
	 * @return 子目录列表
	 */
	public static ArrayList<File> getDiretoryOnly(File dir) {
		ArrayList<File> dirs = new ArrayList<File>();
		if (dir != null && dir.exists() && dir.isDirectory()) {
			File[] files = dir.listFiles(new FileFilter() {
				//@Override
				public boolean accept(File file) {
					if (file.isDirectory())
						return true;
					return false;
				}
			});
			for (int i = 0; i < files.length; i++) {
				dirs.add(files[i]);
			}
		}
		return dirs;
	}

	/**
	 * 列出子文件列表
	 * 
	 * @param dir
	 *            指定目录
	 * @return 子文件列表
	 */
	public ArrayList<File> getFileOnly(File dir) {
		ArrayList<File> dirs = new ArrayList<File>();
		File[] files = dir.listFiles(new FileFilter() {
			//@Override
			public boolean accept(File file) {
				if (file.isFile())
					return true;
				return false;
			}
		});
		for (int i = 0; i < files.length; i++) {
			dirs.add(files[i]);
		}
		return dirs;
	}

	/**
	 * 删除文件
	 * 
	 * @param path
	 * @return
	 */
	public static boolean deleteFile(String path) {
		File file = new File(path);
		return file.delete();
	}

	/**
	 * 文件拷贝
	 * 
	 * @param from
	 * @param to
	 * @return
	 */
	public static boolean copyFile(String from, String to) {
		File fromFile = new File(from);
		File toFile = new File(to);
		FileInputStream fis = null;
		FileOutputStream fos = null;

		try {
			fis = new FileInputStream(fromFile);
			fos = new FileOutputStream(toFile);
			int bytesRead;
			byte[] buf = new byte[4 * 1024]; // 4K buffer
			while ((bytesRead = fis.read(buf)) != -1) {
				fos.write(buf, 0, bytesRead);
			}

		} catch (IOException e) {
			throw new RuntimeException(e);
		} finally {
			try {
				fos.flush();
				fos.close();
				fis.close();
			} catch (IOException ignore) {
			}
		}
		return true;
	}

	/**
	 * 备份文件。 如果有备份文件，先删除。
	 * 
	 * @param filePath
	 */
	public static void backupFile(String filePath) {
		String backupName = filePath + ".bak";
		File file = new File(backupName);
		if (file.exists())
			file.delete();
		copyFile(filePath, backupName);
	}

	/**
	 * 取得文件扩展名
	 * 
	 * @return
	 */
	public static String getFileExt(File file) {
		if (file.isFile())
			return getFileExt(file.getName());
		return "";
	}

	/**
	 * 根据文件名获取扩展名称。
	 * 
	 * @param fileName
	 * @return
	 */
	public static String getFileExt(String fileName) {
		int pos = fileName.lastIndexOf(".");
		if (pos > -1)
			return fileName.substring(pos + 1).toLowerCase();
		return "";
	}

	/**
	 * 复制目录
	 * 
	 * @param fromDir
	 *            源目录
	 * @param toDir
	 *            目标目录
	 * @throws IOException
	 */
	public static void copyDir(String fromDir, String toDir) throws IOException {
		(new File(toDir)).mkdirs();
		File[] file = (new File(fromDir)).listFiles();
		for (int i = 0; i < file.length; i++) {
			if (file[i].isFile()) {
				String fromFile = file[i].getAbsolutePath();
				String toFile = toDir + "/" + file[i].getName();

				copyFile(fromFile, toFile);
			}
			if (file[i].isDirectory())
				copyDirectiory(fromDir + "/" + file[i].getName(), toDir + "/" + file[i].getName());
		}
	}

	/**
	 * 递规调用目录拷贝。
	 * 
	 * @param fromDir
	 *            源目录
	 * @param toDir
	 *            目标目录
	 * @throws IOException
	 */
	private static void copyDirectiory(String fromDir, String toDir) throws IOException {
		(new File(toDir)).mkdirs();
		File[] file = (new File(fromDir)).listFiles();
		for (int i = 0; i < file.length; i++) {
			if (file[i].isFile()) {
				String fromName = file[i].getAbsolutePath();
				String toFile = toDir + File.separator + file[i].getName();
				copyFile(fromName, toFile);
			}
			if (file[i].isDirectory())
				copyDirectiory(fromDir + File.separator + file[i].getName(),
						toDir + File.separator + file[i].getName());
		}
	}

	/**
	 * 取得文件大小
	 * 
	 * @return 返回文件大小
	 * @throws IOException
	 */
	public static String getFileSize(File file) throws IOException {
		if (file.isFile()) {
			FileInputStream fis = new FileInputStream(file);
			int size = fis.available();
			fis.close();
			return getSize((double) size);
		}
		return "";
	}

	/**
	 * 根据字节大小获取带单位的大小。
	 * 
	 * @param size
	 * @return
	 */
	public static String getSize(double size) {
		DecimalFormat df = new DecimalFormat("0.00");
		if (size > 1024 * 1024) {
			double ss = size / (1024 * 1024);
			return df.format(ss) + " M";
		} else if (size > 1024) {
			double ss = size / 1024;
			return df.format(ss) + " KB";
		} else {
			return size + " bytes";
		}
	}

	/**
	 * 取得文件的相对父目录
	 * 
	 * @param baseDir
	 *            基准目录
	 * @param currentFile
	 *            当前文件
	 * @return 相对基准目录路径
	 */
	public static String getParentDir(String baseDir, String currentFile) {
		File f = new File(currentFile);
		String parentPath = f.getParent();
		String path = parentPath.replace(baseDir, "");
		return path.replace(File.separator, "/");
	}

	/**
	 * 根据键在属性文件中获取数据。
	 * 
	 * @param fileName
	 *            属性文件名称。
	 * @param key
	 *            属性的键值。
	 * @return
	 */
	public static String readFromProperties(String fileName, String key) {
		String value = "";
		InputStream stream = null;
		try {
			stream = new BufferedInputStream(new FileInputStream(fileName));
			Properties prop = new Properties();
			prop.load(stream);
			value = prop.getProperty(key);
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			if (stream != null) {
				try {
					stream.close();
				} catch (IOException ignore) {
				}
			}
		}
		return value;
	}

	/**
	 * 保存属性文件。
	 * 
	 * @param fileName
	 *            文件名
	 * @param key
	 *            键名
	 * @param value
	 *            键值
	 * @return 保存是否成功。
	 */
	public static boolean saveProperties(String fileName, String key, String value) {
		StringBuffer sb = new StringBuffer();
		boolean isFound = false;
		BufferedReader in = null;
		try {
			in = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), StringPool.UTF_8));
			String str;
			while ((str = in.readLine()) != null) {
				if (str.startsWith(key)) {
					sb.append(key + "=" + value + "\r\n");
					isFound = true;
				} else {
					sb.append(str + "\r\n");
				}
			}
			// 添加新的键值。
			if (!isFound) {
				sb.append(key + "=" + value + "\r\n");
			}
			FileUtil.writeFile(fileName, sb.toString(), StringPool.UTF_8);
			return true;
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException ignore) {
				}
			}
		}
	}

	/**
	 * 删除属性key。
	 * 
	 * @param fileName
	 * @param key
	 * @return
	 */
	public static boolean delProperties(String fileName, String key) {
		StringBuffer sb = new StringBuffer();

		BufferedReader in = null;
		try {
			in = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), "utf-8"));
			String str;
			while ((str = in.readLine()) != null) {
				if (!str.startsWith(key)) {
					sb.append(str + "\r\n");
				}
			}
			FileUtil.writeFile(fileName, sb.toString(), "utf-8");
			return true;
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException ignore) {
				}
			}
		}
	}

	/**
	 * 获取接口的所有实现类
	 * 
	 * @param interfaceClass
	 *            接口类
	 * @param samePackage
	 *            是否为同一包路径下
	 * @return
	 * @throws ClassNotFoundException
	 * @throws IOException
	 */
	public static List<Class<?>> getAllClassesByInterface(Class<?> interfaceClass, boolean samePackage)
			throws IOException, ClassNotFoundException, IllegalStateException {

		if (!interfaceClass.isInterface()) {
			throw new IllegalStateException("Class not a interface.");
		}

		ClassLoader $loader = interfaceClass.getClassLoader();
		/** 获取包名称 */
		String packageName = samePackage ? interfaceClass.getPackage().getName() : "/";
		return findClasses(interfaceClass, $loader, packageName);
	}

	/**
	 * 获取实现接口的实现类文件
	 * 
	 * @param interfaceClass
	 * @param loader
	 * @param packageName
	 * @return
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	private static List<Class<?>> findClasses(Class<?> interfaceClass, ClassLoader loader, String packageName)
			throws IOException, ClassNotFoundException {

		List<Class<?>> allClasses = new ArrayList<Class<?>>();
		/** 获取包路径 */
		String packagePath = packageName.replace(".", "/");
		if (!packagePath.equals("/")) {
			Enumeration<URL> resources = loader.getResources(packagePath);
			while (resources.hasMoreElements()) {
				URL $url = resources.nextElement();
				allClasses.addAll(findResources(interfaceClass, new File($url.getFile()), packageName));
			}
		} else {
			String path = loader.getResource("").getPath();
			allClasses.addAll(findResources(interfaceClass, new File(path), packageName));
		}
		return allClasses;
	}

	/**
	 * 获取文件资源信息
	 * 
	 * @param interfaceClass
	 * @param directory
	 * @param packageName
	 * @return
	 * @throws ClassNotFoundException
	 */
	@SuppressWarnings("unchecked")
	private static List<Class<?>> findResources(Class<?> interfaceClass, File directory, String packageName)
			throws ClassNotFoundException {

		List<Class<?>> $results = new ArrayList<Class<?>>();
		if (!directory.exists())
			return Collections.EMPTY_LIST;
		File[] files = directory.listFiles();
		for (File file : files) {
			if (file.isDirectory()) {
				// 文件夹-->继续遍历
				if (!file.getName().contains(".")) {
					if (!packageName.equals("/")) {
						$results.addAll(findResources(interfaceClass, file, packageName + "." + file.getName()));
					} else {
						$results.addAll(findResources(interfaceClass, file, file.getName()));
					}
				}
			} else if (file.getName().endsWith(".class")) {
				Class<?> clazz = null;
				if (!packageName.equals("/")) {
					clazz = Class.forName(packageName + "." + file.getName().substring(0, file.getName().length() - 6));
				} else {
					clazz = Class.forName(file.getName().substring(0, file.getName().length() - 6));
				}
				if (interfaceClass.isAssignableFrom(clazz) && !interfaceClass.equals(clazz)) {
					$results.add(clazz);
				}
			}
		}
		return $results;
	}

	/**
	 * 深度克隆对象。
	 * 
	 * <pre>
	 * 	将一个对象序列化一个内存数据组。
	 *  在从数组中反序列化这个类。
	 * </pre>
	 * 
	 * @param obj
	 * @return
	 * @throws Exception
	 */
	public static Object cloneObject(Object obj) throws Exception {
		ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
		ObjectOutputStream out = new ObjectOutputStream(byteOut);
		out.writeObject(obj);
		out.close();

		ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
		ObjectInputStream in = new ObjectInputStream(byteIn);

		Object rtn = in.readObject();
		in.close();
		return rtn;
	}

	/**
	 * 获取classes路径。
	 * 
	 * @return 返回如下的路径E:/ibps/ibps-base-root/modules/ibps-base-core/target/
	 *         classes 。
	 */
	public static String getClassesPath() {
		String path = FileUtil.class.getClassLoader().getResource("").getPath();
		if ("\\".equals(File.separator)) {
			path = StringUtil.trimPrefix(path, "/");
		}
		path = path.replace("\\", "/");
		path = StringUtil.trimSuffix(path, "/");
		return path.replaceAll("%20", " ");
	}

	/**
	 * 获取应用程序根路径。
	 * 
	 * @return 返回如下路径 E:/ibps/src/main/webapp
	 */
	public static String getWebRootPath() {
		String path = getClassesPath();
		path = path.substring(0, path.lastIndexOf("WEB-INF"));
		path = StringUtil.trimSuffix(path, "/");
		return path;
	}
	
}
